﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SeaBattle.Domain.Abstract;
using SeaBattle.Domain.Abstract.Services;

namespace SeaBattle.Domain.Entities
{
    public enum GameState
    {
        STATE_CREATED = 0,
        STATE_GAME_SETUP,
        STATE_OPENED,
        STATE_BOARD_SETUP, // Setup game board
        STATE_PLAY,
        STATE_PAUSE,
        STATE_CLOSED
    }

    public class Game
    {
        public Game(int id, DateTime created, Player creator)
        {
            Id = id;
            Created = created;
            Creator = creator;
            State = GameState.STATE_CREATED;
        }
        
        public Game(int id, DateTime created, Player creator, IShipRepository shipRepository, IFleetRepository fleetRepository, IPlayerRepository playerRepository)
        {
            Id = id;
            Created = created;
            Creator = creator;
            State = GameState.STATE_CREATED;
            this.shipRepository = shipRepository;
            this.playerRepository = playerRepository;
            this.fleetRepository = fleetRepository;
        }

        private void InitializeFleet(Player player)
        {
            Fleet fleet = fleetRepository.CreateFleet(0, 0);
            Navies.Add(player, fleet);
        }

        private Player opponent;
        public int Id { get; private set; }
        public int Preset { get; set; }
        public DateTime Created { get; private set; }
        public Player Creator { get; private set; }
        public GameState State { get; private set; }
        public Dictionary<Player, Fleet> Navies { get; set; }

        private IFleetRepository fleetRepository;
        private IShipRepository shipRepository;
        private IPlayerRepository playerRepository;

        public Player Opponent { get { return opponent; } set { SetOpponent(value); } }        

        private void SetOpponent(Player theOpponent)
        {
            //the game must be STATE_OPENED
            if (!Opened)
            {
                throw new Exception("The game " + Id + " not opened");
            }
            //Check whether Creator and Opponent are not the same persons
            if (Creator == theOpponent)
            {
                throw new Exception("The opponent is the same as creator of the game" + Id);
            }
            //Set opponent
            opponent = theOpponent;
        }

        public void JoinOpponent(Player theOpponent)
        {
            Opponent = theOpponent;
            BoardPreparing = true;
        }            

        public bool Opened
        {
            get { return State == GameState.STATE_OPENED; }
            set
            {
                // Do something
                if (value)
                {
                    State = GameState.STATE_OPENED;
                }
            }
        }

        public bool Closed
        {
            get { return State == GameState.STATE_CLOSED; }
            set
            {
                // Do something
                if (value)
                {
                    State = GameState.STATE_CLOSED;
                }
            }
        }

        public bool BoardPreparing
        {
            get { return State == GameState.STATE_BOARD_SETUP; }
            set
            {
                //Do something
                if (value)
                {
                    State = GameState.STATE_BOARD_SETUP;
                    Navies = new Dictionary<Player, Fleet>();
                    InitializeFleet(Creator);
                    InitializeFleet(Opponent);
                }
            }
        }

        public Ship AddShip(Player player, int x, int y, byte partsCount, bool layout)
        {
            if (!BoardPreparing)
                throw new Exception("Game isn't in BOARD_SETUP state");

            if (!Navies.ContainsKey(player))
                throw new Exception("Not such player in this game");

            Ship ship = shipRepository.CreateShip(x, y, partsCount);
            Navies[player].AddShip(ship, layout);
            return ship;
        }

        public void RemoveShip(int id)
        {
            if (!BoardPreparing)
                throw new Exception("Game isn't in BOARD_SETUP state");

            Ship ship = shipRepository.GetShip(id);

            if (ship == null)
                throw new Exception("Any ship in this game with id" + id.ToString());

            // In case Creator owns the ship
            Navies[Creator].RemoveShip(ship);

            // In case Opponent owns the ship
            Navies[Opponent].RemoveShip(ship);

            // Remove ship from ShipRepository
            shipRepository.RemoveShip(ship);
        }

        public void ResetFleet(int playerId)
        {
            if (!BoardPreparing)
                throw new Exception("Game isn't in BOARD_SETUP state");

            Player player = playerRepository.GetPlayer(playerId);

            if (Creator != player && Opponent != player)
            {
                throw new Exception("Not such player in this game");
            }

            Navies[player].ResetFleet();
        }
    }
}